package com.hex.ds.hdtp.core.app.dqc.service.impl;

import cn.hutool.core.util.StrUtil;
import com.hex.ds.hdtp.core.app.common.page.PageData;
import com.hex.ds.hdtp.core.app.common.page.converter.IPageAndPageDtoConverter;
import com.hex.ds.hdtp.core.app.common.page.dto.PageDto;
import com.hex.ds.hdtp.core.app.dqc.converter.IDqcTaskConverter;
import com.hex.ds.hdtp.core.app.dqc.dto.request.DqcTaskRequestDto;
import com.hex.ds.hdtp.core.app.dqc.dto.response.DqcTaskResponseDto;
import com.hex.ds.hdtp.core.app.dqc.service.IDqcTaskService;
import com.hex.ds.hdtp.core.app.metadata.service.impl.SourceInfoService;
import com.hex.ds.hdtp.core.inf.common.page.Page;
import com.hex.ds.hdtp.core.inf.common.utils.JdbcConnectUtil;
import com.hex.ds.hdtp.core.inf.data.contrast.service.impl.GaussInfoService;
import com.hex.ds.hdtp.core.inf.dqc.po.DqcAuditLogPo;
import com.hex.ds.hdtp.core.inf.dqc.po.DqcTaskPo;
import com.hex.ds.hdtp.core.inf.dqc.repository.IDqcTaskRepository;
import com.hex.ds.hdtp.core.inf.dqc.repository.impl.DqcTaskLogRepository;
import com.hex.ds.hdtp.core.inf.metadata.po.SourceConfInfoPo;
import com.hex.ds.hdtp.core.inf.metadata.po.SourceInfoPo;
import com.hex.ds.hdtp.core.inf.metadata.repository.impl.SourceConfInfoRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class DqcTaskService implements IDqcTaskService {

    private final IDqcTaskRepository dqcTaskRepository;

    private final IDqcTaskConverter converter;

    private final IPageAndPageDtoConverter pageAndPageDtoConverter;

    private final SourceInfoService sourceInfoService;

    private final SourceConfInfoRepository sourceConfInfoRepository;

    private final DqcTaskLogRepository dqcTaskLogRepository;

    private final GaussInfoService gaussInfoService;

    final static String PRIMARY_KEY_CHECK_SQL_PATTERN = "select sum(result) as result from (select count(1) as result from %s.%s where 1=1  group by %s having count(1) >1) a";

    /**
     * @Method queryListByPage
     * @param dqcTaskRequestDto
     * @param pageDto
     * @Return com.hex.ds.hdtp.core.app.common.page.PageData
     * @Description Dqc任务-分页查询
     * @Author Yin.Yang
     * @Date 2023/11/5 21:52
     * @Version V1.0
     */
    @Override
    public PageData queryListByPage(DqcTaskRequestDto dqcTaskRequestDto, PageDto pageDto) {
        final Page<DqcTaskPo> pageResult = dqcTaskRepository.queryListByPage(
                converter.toDqcTaskPo(dqcTaskRequestDto), pageAndPageDtoConverter.toPage(pageDto));
        List<DqcTaskResponseDto> responseDtos = converter.toScriptConvertTaskResponseDtoList(pageResult.getData());
        return new PageData(responseDtos, pageResult.getTotal());
    }

    /**
     * @Method add
     * @param dqcTaskRequestDto
     * @Return void
     * @Description Dqc-新增
     * @Author Yin.Yang
     * @Date 2023/11/5 21:49
     * @Version V1.0
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void add(DqcTaskRequestDto dqcTaskRequestDto) {
        try {
            dqcTaskRequestDto.setPkId(null);
            dqcTaskRepository.addWithBackPkId(converter.toDqcTaskPo(dqcTaskRequestDto));
        } catch (Exception e) {
            throw new RuntimeException("新增Dqc任务失败" + e.getMessage());
        }
    }

    /**
     * @Method modifyById
     * @param dqcTaskRequestDto
     * @Return void
     * @Description Dqc-根据主键修改
     * @Author Yin.Yang
     * @Date 2023/11/5 21:48
     * @Version V1.0
     */
    @Override
    public void modifyById(DqcTaskRequestDto dqcTaskRequestDto) {
        int count = dqcTaskRepository.modifyById(converter.toDqcTaskPo(dqcTaskRequestDto));
        if (count != 1) {
            throw new RuntimeException("修改Dqc任务失败");
        }
    }

    /**
     * @Method removeById
     * @param pkId
     * @Return void
     * @Description Dqc任务-根据pkId删除
     * @Author Yin.Yang
     * @Date 2023/11/5 21:47
     * @Version V1.0
     */
    @Override
    public void removeById(String pkId) {
        int count = dqcTaskRepository.removeById(pkId);
        if (count != 1) {
            throw new RuntimeException("删除Dqc任务失败");
        }
    }

    /**
     * @Method addWithBackId
     * @param dqcTaskRequestDto
     * @Return java.lang.String
     * @Description 新增任务并返回PkId
     * @Author Yin.Yang
     * @Date 2023/11/5 21:44
     * @Version V1.0
     */
    @Override
    public String addWithBackId(DqcTaskRequestDto dqcTaskRequestDto) {
        return dqcTaskRepository.addWithBackPkId(converter.toDqcTaskPo(dqcTaskRequestDto));
    }

    /**
     * @Method modifyRulesById
     * @Param dqcTaskRequestDto
     * @Return void
     * @Description 更新规则
     * @Author gj.xu
     * @Date 2023/12/27 14:20
     * @Version V2.0
     */
    @Override
    public void modifyRulesById(DqcTaskRequestDto dqcTaskRequestDto) {
        dqcTaskRequestDto.setIsRule(true);
        int count = dqcTaskRepository.modifyRulesById(converter.toDqcTaskPo(dqcTaskRequestDto));
        if (count != 1) {
            throw new RuntimeException("修改Dqc规则失败");
        }
    }

    /**
     * @Method batchRemoveById
     * @param pkIds
     * @Return void
     * @Description Dqc任务-批量删除
     * @Author Yin.Yang
     * @Date 2023/11/5 21:59
     * @Version V1.0
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchRemoveById(List<String> pkIds) {
        for (String pkId : pkIds) {
            removeById(pkId);
        }
    }
    /**
     * @Method tryRun
     * @Param
     * @Param pkId
     * @Return java.lang.String
     * @Description 试跑
     * @Author xin.zhao
     * @Date 2023/11/6 14:44
     * @Version V1.0
     */
    @Override
    public String tryRun(String pkId) {
        DqcTaskPo dqcTaskPo = dqcTaskRepository.queryById(pkId);
        DqcAuditLogPo dqcAuditLogPo = converter.toLog(dqcTaskPo);
        if (StrUtil.isEmpty(dqcTaskPo.getSourceConnPkId())){
            return "dataSource absent";
        }
        if (StrUtil.isEmpty(dqcTaskPo.getRuleType())){
            return "ruleType absent";
        }
        try {
            SourceInfoPo sourceInfoPo = sourceInfoService.queryByPkId(dqcTaskPo.getSourceConnPkId());
            List<String> fields = gaussInfoService.selectFieldName(sourceInfoPo.getSourceCode(), dqcTaskPo.getSchemaName(), dqcTaskPo.getTableName());
            if (!fields.contains(dqcTaskPo.getInspectCondition().toUpperCase())){
                return "inspectCondition absent";
            }
            List<SourceConfInfoPo> sourceConfInfoPos = sourceConfInfoRepository.queryListBySourceCode(sourceInfoPo.getSourceCode());
            String stringResult = JdbcConnectUtil.getStringResult(sourceConfInfoPos, String.format(PRIMARY_KEY_CHECK_SQL_PATTERN, dqcTaskPo.getSchemaName(), dqcTaskPo.getTableName(), dqcTaskPo.getInspectCondition()));
            String result;
            if (StrUtil.isEmpty(stringResult)){
                result = "success";
            }else {
                result = "fail";
            }
            LocalDate currentDate = LocalDate.now();
            LocalDateTime currentDateTime = LocalDateTime.now();
            DateTimeFormatter systemFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            DateTimeFormatter noticeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String systemDate = currentDate.format(systemFormatter);
            String noticeDate = currentDateTime.format(noticeFormatter);
//            dqcAuditLogPo.setContent(dqcTaskPo.getJobName()+" | "+dqcTaskPo.getRuleType());
            dqcAuditLogPo.setContent(dqcTaskPo.getJobName()+" | 主键检查");
            dqcAuditLogPo.setStatus(result);
            dqcAuditLogPo.setPkId(null);
            dqcAuditLogPo.setSystemTime(systemDate);
            dqcAuditLogPo.setFinishTime(noticeDate);
            dqcTaskLogRepository.add(dqcAuditLogPo);
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
        return "success";
    }

}
